/**
 * 
 */
package org.vsg.stock.extension.service;

import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Vector;

import org.vsg.stock.basic.DailyStock;
import org.vsg.stock.basic.algorithm.AnalysisIndex;
import org.vsg.stock.basic.domain.StockDailyLine;

/**
 * @author Bill Vison
 *
 */
public class DailyContentHandler {
	
	private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
	
	private DecimalFormat nf = new DecimalFormat("##0.00000");
	
	private DecimalFormat nf2 = new DecimalFormat("##0.0000");
	
	private DecimalFormat nf3 = new DecimalFormat("##0.000");
	
	private List<Double> ratioList = new LinkedList<Double>();
	
	private List<Integer> positionList;
	
	private StringBuilder detailShapeSign = new StringBuilder();
	
	private Vector<DailyStock> dsEntities;


	/**
	 * handle the connent defined
	 * @param content
	 */
	public void handle(List<String> content , String stockCode) {
		
		Vector<DailyStock> entities = new Vector<DailyStock>();
		
		int cycle = 20;
		
		// --- add the content list 
		for (int i = 0 ; i < content.size() ; i++) {
			String line = content.get(i);
			String[] lineData = line.split(",");
			
			String dateStr = lineData[1];
			double open = Double.parseDouble( lineData[2] ) ;
			double close = Double.parseDouble( lineData[5] );
			double high = Double.parseDouble( lineData[3] );
			double low = Double.parseDouble( lineData[4] );
			double vol = Double.parseDouble( lineData[6] );
			double trasValue = Double.parseDouble( lineData[7] );
			double yieldRate =  Double.parseDouble( lineData[8] );			

			StockDailyLine entity = new StockDailyLine();
			entity.setStockCode( stockCode );
			try {
				entity.setDate( sdf.parse( dateStr ) );
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			entity.setOpen(open);
			entity.setHigh(high);
			entity.setLow(low);
			entity.setClose(close);
			entity.setVol((long)vol);
			entity.setTransactionValue(trasValue);
			entity.setYieldRate( yieldRate );
			
			if (i == 0) {
				entity.setExRights( (short)0);
			} else {
				String lastLine = content.get(i-1);
				String[] lastlineData = lastLine.split(",");
				double lastClose = Double.parseDouble( lastlineData[5] );
				
				double realRate = Double.parseDouble( nf.format( (close - lastClose) / lastClose )  );
				if (realRate != yieldRate) {
					entity.setExRights( (short)1 );
				}				
			}

			entities.add( entity );
		}
		
		dsEntities = entities;
		
		positionList = handleEntities( entities,  20 );

	}
	
	public String getShapeSign() {
		StringBuilder shapeSign = new StringBuilder();
		int posi1 = 0;
		int posi2 = 0;
		for (int i = 0 ;i < positionList.size()-1 ; i++) {
			
			if (i == 0) {
				posi1 = ratioList.size();
				posi2 = positionList.get(i);				
			} else {
				posi1 = positionList.get(i-1);
				posi2 = positionList.get(i);
			}
			double sumvalue = 0;
			int  dist = posi1 - posi2;
			double avg = 0;
			for (int j = posi2 ; j < posi1 ;j++) {
				double tmpValue = ratioList.get( j );
				sumvalue+=tmpValue;
			}
			avg = sumvalue / dist;				
			
			;
			// --- check the value ---
			if (avg > 1) {
				shapeSign.append("u");
				detailShapeSign.append("u:").append(nf2.format( avg )).append(",").append( sdf.format( dsEntities.get( posi2 ).getDate() ) ).append(",").append( sdf.format( dsEntities.get( posi1-1 ).getDate() ) ).append(",").append(dist).append("#");
			} else if (avg < -1) {
				shapeSign.append("d");
				detailShapeSign.append("d:").append(nf2.format( avg )).append(",").append( sdf.format( dsEntities.get( posi2 ).getDate() ) ).append(",").append( sdf.format( dsEntities.get( posi1-1 ).getDate() ) ).append(",").append(dist).append("#");
			} else {
				shapeSign.append("s");
				detailShapeSign.append("s:").append(nf2.format( avg )).append(",").append( sdf.format( dsEntities.get( posi2 ).getDate() ) ).append(",").append( sdf.format( dsEntities.get( posi1-1 ).getDate() ) ).append(",").append(dist).append("#");				
			}			

		}
		return shapeSign.toString();
	}

	
	public String getDetailSign() {
		return detailShapeSign.toString();
	}
	
	private List<Integer> handleEntities(List<DailyStock> entities ,  int cycle) {
		List<Integer> markPostionList = new Vector<Integer>();
		
		if (entities.size() - cycle >= 0) {
			AnalysisIndex anaIndex = new AnalysisIndex(entities);
			
			Queue<Integer> markIndexList = new LinkedList<Integer>();
			int upZeroCount = 0;
			int downZeroCount = 0;
			int upOneCount = 0;
			int equalZeroCount = 0;
			int downNegativeOne = 0;
			
			short changeState = 0;
			
			DailyStock ds = null;

			for (int i = entities.size()-1 ; i >= 0  ; i--) {
				ds = entities.get(i);
				// --- not get the last value ---
				double sumtotal = 0;
				if (i - 5 >= 0) {
					double currentValue = anaIndex.medianPoint(ds.getDate() , cycle);
					double lastValue = anaIndex.medianPoint(entities.get(i - 1).getDate() , cycle);
					double last2Value = anaIndex.medianPoint(entities.get(i - 2).getDate() , cycle);
					double last3Value = anaIndex.medianPoint(entities.get(i - 3).getDate() , cycle);
					double last4Value = anaIndex.medianPoint(entities.get(i - 4).getDate() , cycle);
					double last5Value = anaIndex.medianPoint(entities.get(i - 5).getDate() , cycle);
					
					double present = lastValue == 0 ? 0 :(currentValue - lastValue) / lastValue * 100 ;
					double lastRatio = last2Value == 0 ? 0 : (lastValue - last2Value) / last2Value * 100;
					double last2Ratio = last3Value == 0 ? 0 : (last2Value - last3Value) / last3Value * 100 ;
					double last3Ratio = last4Value == 0 ? 0 : (last3Value - last4Value) / last4Value * 100 ;
					double last4Ratio = last5Value == 0 ? 0:(last4Value - last5Value) / last5Value * 100;

					sumtotal = Double.parseDouble( nf2.format( present + lastRatio + last2Ratio + last3Ratio ) ) ;
					double lastSumTotal = last4Ratio + lastRatio + last2Ratio + last3Ratio;
					
					if (sumtotal > 0) {
						++upZeroCount;
						if (sumtotal > 1) {
							// -- tigger handle ---
							++upOneCount;
							if (lastSumTotal <=1) {
								changeState = 1;
							}
						} else {
							// --- set another handle ---
							if (lastSumTotal < 0 || lastSumTotal > 1) {
								changeState = 2;
							}
						}
					}
					else if (sumtotal < 0) {
						++downZeroCount;
						if (sumtotal < -1) {
							++downNegativeOne;
							if (lastSumTotal > -1) {
								changeState = 3;
							}
						} else {
							if (lastSumTotal < -1 || lastSumTotal >=0) {
								changeState = 4;
							}
						}
					}
					else {
						++equalZeroCount;
					}
					
					// --- check the account for the value , trigger handle ---
					if (changeState != 0) {
						markIndexList.add( i );
					}
					if ( changeState == 1 ) {
						upOneCount = 0;
						changeState = 0;
					}
					else if ( changeState == 2) {
						upZeroCount = 0;
						changeState = 0;				
					}
					else if ( changeState == 3) {
						downNegativeOne = 0;
						changeState = 0;				
					}
					else if ( changeState == 4) {
						downZeroCount = 0;
						changeState = 0;							
					}
				}
				ratioList.add( Double.parseDouble( nf2.format( sumtotal ) ) );
				
			}
			
			Collections.reverse( ratioList );
			
			// --- rescan the mark index ---
			int lastPostion =  ratioList.size();
			int prePostion = 0;
			int currentPostion = 0;
			
			boolean isFirst = true;
			while (!markIndexList.isEmpty()) {
				if (isFirst) {
					currentPostion = markIndexList.poll();
					isFirst = false;
				} else {
					currentPostion = prePostion;
				}
				prePostion = markIndexList.poll();
				
				// -- find the preDist Defined ---
				do {
					// skip the mark index 
					if (markIndexList.isEmpty()) {
						break;
					}
					
					int pre2Postion = markIndexList.poll();
					int preDist = prePostion - pre2Postion;
					
					if (preDist < 10) {
						
						if (preDist > 3) {
							double sumvalue = 0;
							boolean same = true;
							boolean overZero = ratioList.get( pre2Postion )>0? true:false;
							double avg = 0;
							for (int j = pre2Postion ; j < prePostion ;j++) {
								double tmpValue = ratioList.get( j );
								if (overZero) {
									if (same && tmpValue < 0) {
										same = false;
									}									
								} else {
									if (same && tmpValue > 0) {
										same = false;
									}									
								}
								sumvalue+=tmpValue;
							}
							avg = sumvalue / preDist;
							if (same) {
								break;
							}							
						}						
						
					} else {
						// check the value field ---
						boolean same = true;
						boolean overZero = ratioList.get( pre2Postion )>0? true:false;						
						for (int j = pre2Postion ; j < prePostion ;j++) {
							double tmpValue = ratioList.get( j );
							if (overZero) {
								if (same && tmpValue < 0) {
									same = false;
								}									
							} else {
								if (same && tmpValue > 0) {
									same = false;
								}									
							}							
						}
						if (same) {
							break;
						}
					}
					prePostion = pre2Postion;					
				} while(true);
				
				// --- add the handle defined ---
				if (lastPostion - currentPostion >= 10) {
					if (!markPostionList.contains( currentPostion )) {
						markPostionList.add( currentPostion );
					}
					lastPostion = currentPostion;					

				} else {
					double sumvalue = 0;
					double avg = 0;
					int currentDist = lastPostion - currentPostion;
					for (int j = currentPostion ; j < lastPostion ;j++) {
						double tmpValue = ratioList.get( j );
						sumvalue+=tmpValue;
					}
					avg = sumvalue / currentDist;
					if (Math.abs(avg) > 1) {
						Date currentDate = entities.get( currentPostion ).getDate();
						if (!markPostionList.contains( currentPostion )) {
							markPostionList.add( currentPostion );
						}
						lastPostion = currentPostion;					
					}
					
				}
			}
	
		}
		return markPostionList;
	}
	

}
